package session

import (
	"context"
	"database/sql"
	"fmt"
	db "gitee.com/cic-cybertwin/ap/db/sqlc"
	"gitee.com/cic-cybertwin/utils/configtools"
	"gitee.com/cic-cybertwin/utils/stringutils"
	_ "github.com/lib/pq"
	log "github.com/sirupsen/logrus"
)

var (
	dbDriver = "postgres"
	dbSource = "postgresql://root:secret@localhost:5432/cybertwin?sslmode=disable"
)

var cybertwinDB *sql.DB

func init() {
	var err error
	if checkDBConfigEmptyValid() {
		dbSource = configtools.DatabaseConfiguration.GetString("dbSource")
		dbDriver = configtools.DatabaseConfiguration.GetString("dbDriver")
		log.WithFields(log.Fields{
			"dbSource": dbSource,
			"dbDriver": dbDriver,
		}).Infof("[dbconn.go]-[init]-使用/config/pgconfig.yaml配置项")
		cybertwinDB, err = sql.Open(dbDriver, dbSource)
		if err != nil {
			log.Fatalln("[dbconn.go]-[init]-无法连接至数据库，检查dbDriver和dbSource常量的设置: error=" + err.Error())
			return
		}
	} else {
		log.Infoln("[dbconn.go]-[init]-无法找到/config/pgconfig.yaml，使用默认的数据库连接配置")
		cybertwinDB, err = sql.Open(dbDriver, dbSource)
		if err != nil {
			log.Fatalln("[dbconn.go]-[init]-无法连接至数据库，检查dbDriver和dbSource常量的设置: error=" + err.Error())
			return
		}
		log.Infoln("[dbcoon.go]-[init]-成功连接至cybertwin数据库")
	}
}

// checkDBConfigValid 当DatabaseConfiguration中的"dbSource"或"dbDriver"中有任意为空，就返回false，否则返回true
func checkDBConfigEmptyValid() bool {
	configtools.DatabaseConfiguration.GetString("dbSource")
	configtools.DatabaseConfiguration.GetString("dbDriver")
	return !stringutils.IsEmpty(configtools.DatabaseConfiguration.GetString("dbSource")) &&
		!stringutils.IsEmpty(configtools.DatabaseConfiguration.GetString("dbDriver"))
}

type DBTXQuery struct {
	*db.Queries
	db *sql.DB
}

func NewDBTXQuery() *DBTXQuery {
	return &DBTXQuery{
		db:      cybertwinDB, // 用于创建事务的，创建事务不能直接用Query
		Queries: db.New(cybertwinDB),
	}
}

func (txQuery *DBTXQuery) execTx(ctx context.Context, fn func(queries *db.Queries) error) error {
	tx, err := txQuery.db.BeginTx(ctx, nil)

	if err != nil {
		return err
	}

	q := db.New(tx)
	err = fn(q)
	if err != nil {
		if rollbackErr := tx.Rollback(); rollbackErr != nil {
			return fmt.Errorf("tx error: %v, rollback err = %v", err, rollbackErr)
		}
		return err
	}
	return tx.Commit()
}

type RegisterTXParam struct {
	InsertRegisteredUeParam db.InsertRegisteredUeParams
	Uid                     string
}

func (txQuery *DBTXQuery) RegisterTX(ctx context.Context, param RegisterTXParam) (db.InsertRegisteredUeRow, error) {
	var res db.InsertRegisteredUeRow
	var err error
	err = txQuery.execTx(ctx, func(txQuery *db.Queries) error {
		// 1. 新增注册设备
		res, err = txQuery.InsertRegisteredUe(ctx, param.InsertRegisteredUeParam)
		if err != nil {
			log.Errorln("[RegisterTX]-[InsertRegisteredUe]-返回error", err.Error())
			return err
		}

		// 2. 关联该设备的user，cybertwin。由于数据库中我已经绑定外键关系，因此不需要在程序里面校验uid和cybertwinid的合法性
		_, err = txQuery.InsertUeDetail(ctx, db.InsertUeDetailParams{
			Ueid:        param.InsertRegisteredUeParam.Ueid,
			Uid:         param.Uid,
			CybertwinID: param.InsertRegisteredUeParam.Cybertwinid,
			Status: sql.NullString{
				String: "OFFLINE",
				Valid:  false,
			},
		})
		if err != nil {
			return err
		}
		return nil
	}, // end of 匿名函数
	)
	return res, err
}

func NewDBQuery() *db.Queries {
	return db.New(cybertwinDB)
}
